package com.sugar.psych.assessment.module.business.service.userleavemessage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sugar.psych.assessment.framework.mybatis.core.dataobject.BaseDO;
import com.sugar.psych.assessment.module.business.controller.admin.userpointsrecord.vo.UserPointsRecordSaveReqVO;
import com.sugar.psych.assessment.module.business.controller.app.userleavemessage.vo.AppUserLeaveMessagePageReqVO;
import com.sugar.psych.assessment.module.business.controller.app.userleavemessage.vo.AppUserLeaveMessageRespVO;
import com.sugar.psych.assessment.module.business.controller.app.userleavemessage.vo.CreateLeaveMsgReqVO;
import com.sugar.psych.assessment.module.business.dal.dataobject.avatarinfo.AvatarInfoDO;
import com.sugar.psych.assessment.module.business.dal.dataobject.psychquestionbank.PsychQuestionBankDO;
import com.sugar.psych.assessment.module.business.dal.dataobject.userleavemessageliked.UserLeaveMessageLikedDO;
import com.sugar.psych.assessment.module.business.dal.mysql.avatarinfo.AvatarInfoMapper;
import com.sugar.psych.assessment.module.business.dal.mysql.userleavemessageliked.UserLeaveMessageLikedMapper;
import com.sugar.psych.assessment.module.business.service.userpointsconfig.UserPointsConfigService;
import com.sugar.psych.assessment.module.business.service.userpointsrecord.UserPointsRecordService;
import com.sugar.psych.assessment.module.business.util.ObjLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.Valid;

import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

import com.sugar.psych.assessment.module.business.controller.admin.userleavemessage.vo.*;
import com.sugar.psych.assessment.module.business.dal.dataobject.userleavemessage.UserLeaveMessageDO;
import com.sugar.psych.assessment.framework.common.pojo.PageResult;
import com.sugar.psych.assessment.framework.common.pojo.PageParam;
import com.sugar.psych.assessment.framework.common.util.object.BeanUtils;

import com.sugar.psych.assessment.module.business.dal.mysql.userleavemessage.UserLeaveMessageMapper;

import static com.sugar.psych.assessment.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.psych.assessment.framework.common.util.collection.CollectionUtils.convertList;
import static com.sugar.psych.assessment.framework.common.util.collection.CollectionUtils.diffList;
import static com.sugar.psych.assessment.module.business.enums.ErrorCodeConstants.*;
import static com.sugar.psych.assessment.module.business.enums.PointRecordClsEnum.CLS4;
import static com.sugar.psych.assessment.module.business.enums.PointRecordClsEnum.CLS6;

/**
 * 用户留言 Service 实现类
 *
 * @author Ysugar
 */
@Slf4j
@Service
@Validated
public class UserLeaveMessageServiceImpl implements UserLeaveMessageService {

    @Resource
    private UserLeaveMessageMapper userLeaveMessageMapper;
    @Resource
    private UserLeaveMessageLikedMapper userLeaveMessageLikedMapper;
    @Resource
    private UserPointsRecordService userPointsRecordService;
    @Resource
    private AvatarInfoMapper avatarInfoMapper;

    @Override
    public Long createUserLeaveMessage(UserLeaveMessageSaveReqVO createReqVO) {
        // 插入
        UserLeaveMessageDO userLeaveMessage = BeanUtils.toBean(createReqVO, UserLeaveMessageDO.class);
        userLeaveMessageMapper.insert(userLeaveMessage);
        // 返回
        return userLeaveMessage.getId();
    }

    @Override
    public void updateUserLeaveMessage(UserLeaveMessageSaveReqVO updateReqVO) {
        // 校验存在
        validateUserLeaveMessageExists(updateReqVO.getId());
        // 更新
        UserLeaveMessageDO updateObj = BeanUtils.toBean(updateReqVO, UserLeaveMessageDO.class);
        userLeaveMessageMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserLeaveMessage(Long id) {
        // 校验存在
        validateUserLeaveMessageExists(id);
        // 删除
        userLeaveMessageMapper.deleteById(id);
    }

    @Override
        public void deleteUserLeaveMessageListByIds(List<Long> ids) {
        // 校验存在
        validateUserLeaveMessageExists(ids);
        // 删除
        userLeaveMessageMapper.deleteByIds(ids);
        }

    private void validateUserLeaveMessageExists(List<Long> ids) {
        List<UserLeaveMessageDO> list = userLeaveMessageMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(USER_LEAVE_MESSAGE_NOT_EXISTS);
        }
    }

    private void validateUserLeaveMessageExists(Long id) {
        if (userLeaveMessageMapper.selectById(id) == null) {
            throw exception(USER_LEAVE_MESSAGE_NOT_EXISTS);
        }
    }

    @Override
    public UserLeaveMessageDO getUserLeaveMessage(Long id) {
        return userLeaveMessageMapper.selectById(id);
    }

    @Override
    public PageResult<UserLeaveMessageRespVO> getUserLeaveMessagePage(UserLeaveMessagePageReqVO pageReqVO) {
        return userLeaveMessageMapper.selectPage(pageReqVO);
    }

    @Override
    public Long appCreateUserLeaveMessage(CreateLeaveMsgReqVO createReqVO, Long loginUserId) {
        UserLeaveMessageDO userLeaveMessageDO = new UserLeaveMessageDO();
        userLeaveMessageDO.setAnonymityName(RandomUtil.randomString(8));
        // 随机头像
        List<AvatarInfoDO> avatarList = avatarInfoMapper.selectList();
        if (CollUtil.isEmpty(avatarList))
            throw exception(AVATAR_INFO_NOT_EXISTS);

        userLeaveMessageDO.setAnonymityAvatar(avatarList.get(RandomUtil.randomInt(0, avatarList.size())).getAvatar());
        userLeaveMessageDO.setUserId(loginUserId).setContent(createReqVO.getContent());
        userLeaveMessageMapper.insert(userLeaveMessageDO);
        return userLeaveMessageDO.getId();
    }

    @Override
    public void appDeleteUserLeaveMessage(Long id, Long loginUserId) {
        userLeaveMessageMapper.delete(Wrappers.<UserLeaveMessageDO>lambdaQuery()
                .eq(UserLeaveMessageDO::getId, id).eq(UserLeaveMessageDO::getUserId, loginUserId));
    }

    @Override
    public PageResult<AppUserLeaveMessageRespVO> appGetUserLeaveMessagePage(PageParam pageParam, Long loginUserId) {
        return BeanUtils.toBean(userLeaveMessageMapper.selectPage(pageParam, Wrappers.<UserLeaveMessageDO>lambdaQuery()
                        .eq(UserLeaveMessageDO::getUserId, loginUserId)
                        .eq(UserLeaveMessageDO::getStatus, 0)
                        .orderByDesc(BaseDO::getCreateTime)), AppUserLeaveMessageRespVO.class,
                r -> r.setLiked(userLeaveMessageLikedMapper.selectCount(Wrappers.<UserLeaveMessageLikedDO>lambdaQuery()
                        .eq(UserLeaveMessageLikedDO::getUserId, loginUserId).eq(UserLeaveMessageLikedDO::getLeaveMessageId, r.getId())) > 0));
    }

    @Override
    public void userLeaveMessageLiked(Long id, Long loginUserId) {
        UserLeaveMessageDO leaveMessage = userLeaveMessageMapper.selectOne(Wrappers.<UserLeaveMessageDO>lambdaQuery()
                .eq(UserLeaveMessageDO::getId, id).eq(UserLeaveMessageDO::getStatus, 0)
                .nested(w -> w.isNull(UserLeaveMessageDO::getValidTime).or().ge(UserLeaveMessageDO::getValidTime, LocalDateTime.now())));
        if (Objects.isNull(leaveMessage))
            throw exception(USER_LEAVE_MESSAGE_NOT_EXISTS);

        ReentrantLock lock = ObjLockUtil.obtainLock(ObjLockUtil.generatorKey("LEAVE_MESSAGE", id));
        try {
            lock.lock();

            Integer likedCount = leaveMessage.getLikedCount();
            UserLeaveMessageLikedDO userLeaveMessageLikedDO = userLeaveMessageLikedMapper.selectOne(Wrappers.<UserLeaveMessageLikedDO>lambdaQuery()
                    .eq(UserLeaveMessageLikedDO::getLeaveMessageId, id).eq(UserLeaveMessageLikedDO::getUserId, loginUserId));

            if (userLeaveMessageLikedDO != null){
                userLeaveMessageLikedMapper.deleteById(userLeaveMessageLikedDO.getId());
                likedCount--;
            } else {
                // 插入点赞信息
                userLeaveMessageLikedMapper.insert(new UserLeaveMessageLikedDO().setLeaveMessageId(id).setUserId(loginUserId));
                likedCount++;
            }

            Boolean isReward = null;

            if (!leaveMessage.getIsReward()) {
                // 判断留言点赞数是否 >= 3
                if (likedCount >= 3){
                    // 赠送用户答题积分
                    UserPointsRecordSaveReqVO reqVO = new UserPointsRecordSaveReqVO();
                    reqVO.setUserId(loginUserId).setCls(CLS6.getValue()).setType(true).setObtainedPoints(4).setTitle("留言被赞 3 次");
                    userPointsRecordService.createUserPointsRecord(reqVO);
                    isReward = true;
                }
            }

            // 更改留言点赞总数
            userLeaveMessageMapper.update(UserLeaveMessageDO::getId, id,
                    UserLeaveMessageDO::getLikedCount, likedCount,
                    UserLeaveMessageDO::getIsReward, isReward);

        }catch (Throwable e){
            log.error("服务异常，请稍后重试:", e);
        }finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    @Override
    public PageResult<AppUserLeaveMessageRespVO> selectUserLeaveMessagePage(AppUserLeaveMessagePageReqVO reqVO, Long loginUserId) {
        LambdaQueryWrapper<UserLeaveMessageDO> wrapper = Wrappers.<UserLeaveMessageDO>lambdaQuery()
                .eq(UserLeaveMessageDO::getStatus, 0)
                .nested(w -> w.isNull(UserLeaveMessageDO::getValidTime).or().ge(UserLeaveMessageDO::getValidTime, LocalDateTime.now()));

        Boolean sortDate = reqVO.getSortDate();
        if (null != sortDate)
            wrapper.orderBy(true, sortDate, UserLeaveMessageDO::getCreateTime);
        Boolean sortLiked = reqVO.getSortLiked();
        if (null != sortLiked)
            wrapper.orderBy(true, sortLiked, UserLeaveMessageDO::getLikedCount);

        PageResult<UserLeaveMessageDO> pageResult = userLeaveMessageMapper.selectPage(reqVO, wrapper);
        return BeanUtils.toBean(pageResult, AppUserLeaveMessageRespVO.class
                , r -> r.setLiked(userLeaveMessageLikedMapper.selectCount(Wrappers.<UserLeaveMessageLikedDO>lambdaQuery()
                        .eq(UserLeaveMessageLikedDO::getUserId, loginUserId).eq(UserLeaveMessageLikedDO::getLeaveMessageId, r.getId())) > 0));
    }

}